#include "StdAfx.h"
#include "netUtil.h"
#include "viafirmaClient.h"



netUtil::netUtil():
m_curlHandle( NULL ),
m_curlProxyParamsSet( false ),
m_curlCallbackParamsSet( false ),
m_proxyServerIp( "" ),
m_proxyServerPort( "" ),
m_proxyUserName( "" ),
m_proxyPassword( "" )
{
    /* Clear error buffer */
    clearCurlCallbackBuffers();

    /* Initialize cURL */
    m_curlHandle = curl_easy_init();
    if( !isCurlInit() )
    {
        std::string dummyStr( "" );
        getLastCurlError( dummyStr );
    }

	// Data to send
	post=NULL;
	last=NULL;
}



netUtil::~netUtil()
{
	 /* Cleanup cURL */
    if( isCurlInit() )
    {
        curl_easy_cleanup( m_curlHandle );
        m_curlHandle = NULL;
    }
}


/*++
* @method: NetUtil::clearCurlCallbackBuffers
*
* @description: method to clear callback buffers used by cURL. this is an
*               internal method and netUtil users need not use this.
*
* @input: none
*
* @output: none
*
*
*--*/
void netUtil::clearCurlCallbackBuffers()
{
    m_callbackData = "";
    memset( m_errorBuffer, 0, netDefaults::CURL_DEFAULT_BUFFSIZE );
}


/*++
* @method: netUtil::prepareCurlProxy
*
* @description: method to set proxy details into cURL. this is an internal method.
*               netUtil users should not use this method, instead use setProxyXxx
*               methods to set proxy server information.
*
* @input: none
*
* @output: none
*
* @remarks: internal method
*
*--*/
void netUtil::prepareCurlProxy()
{
    if( !m_curlProxyParamsSet && m_proxyUserName.length() && m_proxyPassword.length() )
    {
        /* Reset existing proxy details in cURL */
        curl_easy_setopt( m_curlHandle, CURLOPT_PROXY, NULL );
        curl_easy_setopt( m_curlHandle, CURLOPT_PROXYUSERPWD, NULL );

        /* Prepare username and password for proxy server */
        std::string proxyIpPort( "" );
        std::string proxyUserPass( "" );
        utilMakeCurlParams( proxyUserPass, getProxyUserName(), getProxyPassword() );
        utilMakeCurlParams( proxyIpPort, getProxyServerIp(), getProxyServerPort() );

        /* Set proxy details in cURL */
        curl_easy_setopt( m_curlHandle, CURLOPT_PROXY, proxyIpPort.c_str() );
        curl_easy_setopt( m_curlHandle, CURLOPT_PROXYUSERPWD, proxyUserPass.c_str() );
        curl_easy_setopt( m_curlHandle, CURLOPT_PROXYAUTH, (long)CURLAUTH_ANY );

        /* Set the flag to true indicating that proxy info is set in cURL */
        m_curlProxyParamsSet = true;
    }
}


/*++
* @method: netUtil::prepareCurlCallback
*
* @description: method to set callback details into cURL. this is an internal method.
*               netUtil users should not use this method.
*
* @input: none
*
* @output: none
*
* @remarks: internal method
*
*--*/
void netUtil::prepareCurlCallback()
{
    if( !m_curlCallbackParamsSet )
    {
        /* Set buffer to get error */
        curl_easy_setopt( m_curlHandle, CURLOPT_ERRORBUFFER, m_errorBuffer );

        /* Set callback function to get response */
        curl_easy_setopt( m_curlHandle, CURLOPT_WRITEFUNCTION, curlCallback );
        curl_easy_setopt( m_curlHandle, CURLOPT_WRITEDATA, this );

        /* Set the flag to true indicating that callback info is set in cURL */
        m_curlCallbackParamsSet = true;
    }
}

/*++
* @method: netUtil::prepareStandardParams
*
* @description: method to set standard params into cURL. this is an internal method.
*               netUtil users should not use this method.
*
* @input: none
*
* @output: none
*
* @remarks: internal method
*
*--*/
void netUtil::prepareStandardParams()
{
    /* Clear callback and error buffers */
    clearCurlCallbackBuffers();

    /* Prepare proxy */
    prepareCurlProxy();

    /* Prepare cURL callback data and error buffer */
    prepareCurlCallback();
}


/*++
* @method: netUtil::performGet
*
* @description: method to send http GET request. this is an internal method.
*               yelpCurl users should not use this method.
*
* @input: getUrl - Yelp query URL
*
* @output: none
*
* @remarks: internal method
*
*--*/
bool netUtil::performGet( const std::string& getUrl )
{
    /* Prepare cURL params */
    prepareStandardParams();

    /* Set http request and url */
    curl_easy_setopt( m_curlHandle, CURLOPT_HTTPGET, 1 );
    curl_easy_setopt( m_curlHandle, CURLOPT_URL, getUrl.c_str() );
	curl_easy_setopt(m_curlHandle, CURLOPT_USERAGENT, VIAFIRMA_CLIENT_VERSION);

	int still_running=0;
	/* lets start the fetch */
	do {
		while(curl_multi_perform(m_curlHandle, &still_running) ==
			CURLM_CALL_MULTI_PERFORM);
	} while (still_running);

    /* Send http request */
    if( CURLE_OK == curl_easy_perform( m_curlHandle ) )
    {
        return true;
    }
    return false;
}


bool netUtil::performPost( const std::string& getUrl,const char * post_fields )
{
   /* Prepare cURL params */
    prepareStandardParams();

    /* Set http request and url */
	curl_easy_setopt(m_curlHandle, CURLOPT_HTTPGET,		0L				);
	curl_easy_setopt(m_curlHandle, CURLOPT_POST,		1L				);
	curl_easy_setopt(m_curlHandle, CURLOPT_POSTFIELDS,	post_fields			);
	curl_easy_setopt(m_curlHandle, CURLOPT_USERAGENT, VIAFIRMA_CLIENT_VERSION);
	curl_easy_setopt( m_curlHandle, CURLOPT_URL, getUrl.c_str() );


	int still_running=0;
	/* lets start the fetch */
	do {
		while(curl_multi_perform(m_curlHandle, &still_running) ==
			CURLM_CALL_MULTI_PERFORM);
	} while (still_running);

    /* Send http request */
    if( CURLE_OK == curl_easy_perform( m_curlHandle ) )
    {
		long http_code = 0;
		curl_easy_getinfo (m_curlHandle, CURLINFO_RESPONSE_CODE, &http_code);
		if (http_code == 200 )
		{
			//Succeeded
			return true;
		}
		else
		{
			 //Failed
			return false;
		}

        return true;
    }
    return false;
}


/*++
* @method: netUtil::getProxyServerIp
*
* @description: method to get proxy server IP address
*
* @input: none
*
* @output: proxy server IP address
*
*--*/
std::string& netUtil::getProxyServerIp()
{
    return m_proxyServerIp;
}

/*++
* @method: netUtil::getProxyServerPort
*
* @description: method to get proxy server port
*
* @input: none
*
* @output: proxy server port
*
*--*/
std::string& netUtil::getProxyServerPort()
{
    return m_proxyServerPort;
}

/*++
* @method: netUtil::getProxyUserName
*
* @description: method to get proxy user name
*
* @input: none
*
* @output: proxy server user name
*
*--*/
std::string& netUtil::getProxyUserName()
{
    return m_proxyUserName;
}

/*++
* @method: netUtil::getProxyPassword
*
* @description: method to get proxy server password
*
* @input: none
*
* @output: proxy server password
*
*--*/
std::string& netUtil::getProxyPassword()
{
    return m_proxyPassword;
}

/*++
* @method: netUtil::setProxyServerIp
*
* @description: method to set proxy server IP address
*
* @input: proxyServerIp
*
* @output: none
*
*--*/
void netUtil::setProxyServerIp( std::string& proxyServerIp )
{
    if( proxyServerIp.length() )
    {
        m_proxyServerIp = proxyServerIp;
        /*
         * Reset the flag so that next cURL http request
         * would set proxy details again into cURL.
         */
        m_curlProxyParamsSet = false;
    }
}

/*++
* @method: netUtil::setProxyServerPort
*
* @description: method to set proxy server port
*
* @input: proxyServerPort
*
* @output: none
*
*--*/
void netUtil::setProxyServerPort( std::string& proxyServerPort )
{
    if( proxyServerPort.length() )
    {
        m_proxyServerPort = proxyServerPort;
        /*
         * Reset the flag so that next cURL http request
         * would set proxy details again into cURL.
         */
        m_curlProxyParamsSet = false;
    }
}

/*++
* @method: netUtil::setProxyUserName
*
* @description: method to set proxy server username
*
* @input: proxyUserName
*
* @output: none
*
*--*/
void netUtil::setProxyUserName( std::string& proxyUserName )
{
    if( proxyUserName.length() )
    {
        m_proxyUserName = proxyUserName;
        /*
         * Reset the flag so that next cURL http request
         * would set proxy details again into cURL.
         */
        m_curlProxyParamsSet = false;
    }
}

/*++
* @method: netUtil::setProxyPassword
*
* @description: method to set proxy server password
*
* @input: proxyPassword
*
* @output: none
*
*--*/
void netUtil::setProxyPassword( std::string& proxyPassword )
{
    if( proxyPassword.length() )
    {
        m_proxyPassword = proxyPassword;
        /*
         * Reset the flag so that next cURL http request
         * would set proxy details again into cURL.
         */
        m_curlProxyParamsSet = false;
    }
}




/*++
* @method: utilMakeCurlParams
*
* @description: utility function to build parameter strings in the format
*               required by cURL ("param1:param2"). netUtil users should
*               not use this function.
*
* @input: inParam1 - first parameter,
*         inParam2 - second parameter
*
* @output: outStr - built parameter
*
* @remarks: internal method
*
*--*/
void utilMakeCurlParams( std::string& outStr, std::string& inParam1, std::string& inParam2 )
{
    outStr = inParam1;
    outStr.append( netDefaults::CURL_COLON.c_str() );
    outStr.append( inParam2.c_str() );
}



/*++
* @method: yelpCurl::curlCallback
*
* @description: static method to get http response back from cURL.
*               this is an internal method, users of yelpCurl need not
*               use this.
*
* @input: as per cURL convention.
*
* @output: size of data stored in our buffer
*
* @remarks: internal method
*
*--*/
int netUtil::curlCallback( char* data, size_t size, size_t nmemb, netUtil* util )
{
    int writtenSize = 0;
    if( ( NULL != util ) && ( NULL != data ) )
    {
        /* Save http response in yelpCurl object's buffer */
        writtenSize = util->saveLastWebResponse( data, ( size*nmemb ) );
    }
    return writtenSize;
}

/*++
* @method: yelpCurl::saveLastWebResponse
*
* @description: method to save http responses. this is an internal method
*               and yelpCurl users need not use this.
*
* @input: data - character buffer from cURL,
*         size - size of character buffer
*
* @output: size of data stored in our buffer
*
* @remaks: internal method
*
*--*/
int netUtil::saveLastWebResponse(  char*& data, size_t size )
{
    int bytesWritten = 0;
    if( data && size )
    {
        /* Append data in our internal buffer */
        m_callbackData.append( data, size );
        bytesWritten = (int)size; 
    }
    return bytesWritten;
}

/*++
* @method: yelpCurl::isCurlInit
*
* @description: method to check if cURL is initialized properly
*
* @input: none
*
* @output: true if cURL is intialized, otherwise false
*
*--*/
bool netUtil::isCurlInit()
{
    return ( NULL != m_curlHandle ) ? true : false;
}

/*++
* @method: yelpCurl::getLastWebResponse
*
* @description: method to get Yelp's http response for the most recent request.
*               yelpCurl users need to call this method and parse the JSON
*               data returned by Yelp to see what has happened.
*
* @input: outWebResp - string in which Yelp's response is supplied back to caller
*
* @output: none
*
*--*/
void netUtil::getLastWebResponse( std::string& outWebResp )
{
    if( m_callbackData.length() )
    {
        outWebResp = m_callbackData;
    }
}

/*++
* @method: netUtil::getLastCurlError
*
* @description: method to get cURL error response for most recent http request.
*               yelpCurl users can call this method if any of the Yelp API methods
*               return false.
*
* @input: outErrResp - string in which cURL's response is supplied back to caller
*
* @output: none
*
*--*/
void netUtil::getLastCurlError( std::string& outErrResp )
{
	m_errorBuffer[netDefaults::CURL_DEFAULT_BUFFSIZE-1] = netDefaults::CURL_EOS;
    outErrResp.assign( m_errorBuffer );
}

/**
Escape html*/
char * netUtil::encode(const char * toEncode){
	return curl_easy_escape(m_curlHandle,toEncode, strlen(toEncode));
}